package com.renren.webmaven2.util;

import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;

import org.apache.commons.lang.time.DateUtils;

/**
 * 
 * @author jizhong
 * 
 */
public class DateUtil {

	public static final String DATE_PATTEN_DEFAULT = "yyyy-MM-dd HH:mm:ss";

	public static final String DATE_PATTEN_DAY = "yyyy-MM-dd";

	public static final String DATE_PATTEN_MONTH = "yyyy-MM";

	public static final String DATE_PATTEN_DAY2 = "yyyyMMdd";

	public static String formatDate(Date date) {
		return formatDate(date, DATE_PATTEN_DEFAULT);
	}

	public static String formatDate(Date date, String patten) {
		if (date == null) {
			return "";
		}
		return getDateFormat(patten).format(date);
	}

	public static Date parseDate(Object param) {
		return parseDate(param, DATE_PATTEN_DEFAULT);
	}

	public static Date parseDate(Object param, String patten) {
		if (param == null) {
			return null;
		}
		try {
			return getDateFormat(patten).parse(param.toString());
		} catch (Exception e) {
			return null;
		}
	}

	public static boolean before(Date sourceDate, Date targetDate) {
		return targetDate.before(sourceDate);
	}

	public static Date getCurrentMonthFirstDat(Date date) {
		Calendar calendar = Calendar.getInstance();
		if (date != null) {
			calendar.setTime(date);
		}
		calendar.set(Calendar.DAY_OF_MONTH, 1);
		calendar.set(Calendar.HOUR_OF_DAY, 0);
		calendar.set(Calendar.MINUTE, 0);
		calendar.set(Calendar.SECOND, 0);
		calendar.set(Calendar.MILLISECOND, 0);
		return calendar.getTime();
	}

	public static String formateNumber(Number n, String patten) {
		return getNumberFormat(patten).format(n);
	}

	/**
	 * Symbol Location Localized? Meaning 0 Number Yes Digit # Number Yes Digit,
	 * zero shows as absent . Number Yes Decimal separator or monetary decimal
	 * separator - Number Yes Minus sign , Number Yes Grouping separator E
	 * Number Yes Separates mantissa and exponent in scientific notation. Need
	 * not be quoted in prefix or suffix. ; Subpattern boundary Yes Separates
	 * positive and negative subpatterns % Prefix or suffix Yes Multiply by 100
	 * and show as percentage \u2030 Prefix or suffix Yes Multiply by 1000 and
	 * show as per mille value ¤ (\u00A4) Prefix or suffix No Currency sign,
	 * replaced by currency symbol. If doubled, replaced by international
	 * currency symbol. If present in a pattern, the monetary decimal separator
	 * is used instead of the decimal separator. ' Prefix or suffix No Used to
	 * quote special characters in a prefix or suffix, for example, "'#'#"
	 * formats 123 to "#123". To create a single quote itself, use two in a row:
	 * "# o''clock".
	 * 
	 * @param patten
	 * @return
	 */
	public static DateFormat getDateFormat(String patten) {
		if (dateFormatMap == null) {
			dateFormatMap = new HashMap<String, DateFormat>();
		}
		if (!dateFormatMap.containsKey(patten)) {
			dateFormatMap.put(patten, new SimpleDateFormat(patten));
			// dateFormatMap.put(patten, new
			// SimpleDateFormat("yyyy-MM-dd HH:mm:ss"))
		}
		return dateFormatMap.get(patten);
	}

	private static Map<String, DateFormat> dateFormatMap;

	public static NumberFormat getNumberFormat(String patten) {
		if (numberFormatMap == null) {
			numberFormatMap = new HashMap<String, NumberFormat>();
		}
		if (!numberFormatMap.containsKey(patten)) {
			numberFormatMap.put(patten, new DecimalFormat(patten));
		}
		return numberFormatMap.get(patten);
	}

	private static Map<String, NumberFormat> numberFormatMap;

	public static Date minuteToDate(long minute) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTimeInMillis(minute * 60000);
		return calendar.getTime();
	}

	public static int dateToMinute(Date date) {
		if (date == null) {
			return 0;
		}
		return (int) (date.getTime() / 60000);
	}

	public static Set<String> getDateArray(Date startDate, Date endDate) {
		DateFormat df = getDateFormat(DATE_PATTEN_DAY);
		if (startDate == null || endDate == null || startDate.after(endDate)) {
			return null;
		}
		Set<String> result = new LinkedHashSet<String>();
		String endStr = df.format(endDate);
		String startStr = null;
		do {
			startStr = df.format(startDate);
			result.add(startStr);
			startDate = DateUtils.addDays(startDate, 1);
		} while (!startStr.equals(endStr));

		return result;
	}

	public static Set<Date> getDateArray2(Date startDate, Date endDate) {
		DateFormat df = getDateFormat(DATE_PATTEN_DAY);
		if (startDate == null || endDate == null || startDate.after(endDate)) {
			return null;
		}
		Set<Date> result = new LinkedHashSet<Date>();
		String endStr = df.format(endDate);
		String startStr = null;
		do {
			startStr = df.format(startDate);
			result.add(startDate);
			startDate = DateUtils.addDays(startDate, 1);
		} while (!startStr.equals(endStr));
		return result;
	}

	public static List<Date> getDateList(Date dBegin, Date dEnd) {
		List<Date> lDate = new ArrayList<Date>();
		lDate.add(dBegin);
		Calendar calBegin = Calendar.getInstance();
		calBegin.setTime(dBegin);
		Calendar calEnd = Calendar.getInstance();
		calEnd.setTime(dEnd);
		while (dEnd.after(calBegin.getTime())) {
			calBegin.add(Calendar.DAY_OF_MONTH, 1);
			lDate.add(calBegin.getTime());
		}
		return lDate;
	}

	public static Set<String> getDates(String startDate, String endDate)
			throws ParseException {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		Date dBegin = sdf.parse(startDate);
		Date dEnd = sdf.parse(endDate);
		return getDateArray(dBegin, dEnd);

	}

	public static Set<String> getMonthArray(Date startDate, Date endDate) {
		if (startDate == null || endDate == null || startDate.after(endDate)) {
			return null;
		}
		DateFormat df = getDateFormat("yyyy-MM");
		Set<String> result = new LinkedHashSet<String>();
		String endStr = df.format(endDate);
		String startStr = null;
		do {
			startStr = df.format(startDate);
			result.add(startStr);
			startDate = DateUtils.addMonths(startDate, 1);
		} while (!startStr.equals(endStr));

		return result;
	}

	public static Map<String, Map<String, Set<Integer>>> getDataQMonthMap(
			Date startDate, Date endDate) {
		DateFormat df = getDateFormat("yyyy-MM");
		if (startDate == null || endDate == null || startDate.after(endDate)) {
			return null;
		}
		Map<String, Map<String, Set<Integer>>> map = new LinkedHashMap<String, Map<String, Set<Integer>>>();
		String endStr = df.format(endDate);
		String startStr = null;
		String qKey = null;
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(startDate);
		do {
			qKey = getQ(calendar);
			Map<String, Set<Integer>> map2 = map.get(qKey);
			if (map2 == null) {
				map2 = new LinkedHashMap<String, Set<Integer>>();
				map.put(qKey, map2);
			}
			Set<Integer> set = new LinkedHashSet<Integer>();
			int j = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
			for (int i = 1; i <= j; i += 1) {
				set.add(i);
			}
			startStr = df.format(calendar.getTime());
			map2.put(startStr, set);
			calendar.add(Calendar.MONTH, 1);
		} while (!startStr.equals(endStr));
		return map;
	}

	public static Set<String> getDateMonthArray(Date startDate, Date endDate) {
		DateFormat df = getDateFormat("yyyy-MM");
		if (startDate == null || endDate == null || startDate.after(endDate)) {
			return null;
		}
		Set<String> result = new LinkedHashSet<String>();
		String endStr = df.format(endDate);
		String startStr = null;
		do {
			startStr = df.format(startDate);
			result.add(startStr);
			startDate = DateUtils.addMonths(startDate, 1);
		} while (!startStr.equals(endStr));

		return result;
	}

	public static Set<String> getDateQArray(Date startDate, Date endDate) {
		if (startDate == null || endDate == null || startDate.after(endDate)) {
			return null;
		}
		Set<String> result = new LinkedHashSet<String>();
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(endDate);

		String endStr = getQ(calendar);
		String startStr = null;
		calendar.setTime(startDate);
		do {
			startStr = getQ(calendar);
			result.add(startStr);
			calendar.add(Calendar.MONTH, 1);
		} while (!startStr.equals(endStr));

		return result;
	}

	public static String getMonth(Date date) {
		if (date == null) {
			return null;
		}
		return formatDate(date, "yyyy-MM");
	}

	public static String getQ(Date date) {
		return getQ(getCalendar(date));
	}

	public static String getQ(Calendar calendar) {
		if (calendar == null) {
			return null;
		}
		return getQ(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH));
	}

	public static String getQ(int year, int month) {
		if (month <= Calendar.MARCH) {
			return year + "-" + "Q1";
		} else if (month <= Calendar.JUNE) {
			return year + "-" + "Q2";
		} else if (month <= Calendar.SEPTEMBER) {
			return year + "-" + "Q3";
		} else {
			return year + "-" + "Q4";
		}
	}

	public static boolean isWeekend(String month, int day) {
		return isWeekend(getCalendar(month, day));
	}

	public static boolean isWeekend(Date date) {
		return isWeekend(getCalendar(date));
	}

	public static boolean isWeekend(Calendar calendar) {
		if (calendar == null) {
			return false;
		}
		int i = calendar.get(Calendar.DAY_OF_WEEK);
		if (i == Calendar.SUNDAY || i == Calendar.SATURDAY) {
			return true;
		} else {
			return false;
		}
	}

	public static String getMonthShort(String month) {
		return getMonthShort(getCalendar(month, 1));
	}

	public static String getMonthShort(String month, int day) {
		return getMonthShort(getCalendar(month, day));
	}

	public static String getMonthShort(Date date) {
		return getMonthShort(getCalendar(date));
	}

	public static String getMonthShort(Calendar calendar) {
		if (calendar == null) {
			return null;
		}
		int i = calendar.get(Calendar.MONTH);
		switch (i) {
		case Calendar.JANUARY:
			return "Jan";
		case Calendar.FEBRUARY:
			return "Feb";
		case Calendar.MARCH:
			return "Mar";
		case Calendar.APRIL:
			return "Apr";
		case Calendar.MAY:
			return "May";
		case Calendar.JUNE:
			return "June";
		case Calendar.JULY:
			return "July";
		case Calendar.AUGUST:
			return "Aug";
		case Calendar.SEPTEMBER:
			return "Sept";
		case Calendar.OCTOBER:
			return "Oct";
		case Calendar.NOVEMBER:
			return "Nov";
		case Calendar.DECEMBER:
			return "Dec";
		}
		return null;
	}

	public static String getWeekShort(String month, int day) {
		return getWeekShort(getCalendar(month, day));
	}

	public static String getWeekShort(Date date) {
		return getWeekShort(getCalendar(date));
	}

	public static String getWeekShort(Calendar calendar) {
		if (calendar == null) {
			return null;
		}
		int i = calendar.get(Calendar.DAY_OF_WEEK);
		switch (i) {
		case Calendar.SUNDAY:
			return "Sun";
		case Calendar.MONDAY:
			return "Mon";
		case Calendar.TUESDAY:
			return "Tues";
		case Calendar.WEDNESDAY:
			return "Wed";
		case Calendar.THURSDAY:
			return "Thurs";
		case Calendar.FRIDAY:
			return "Fri";
		case Calendar.SATURDAY:
			return "Sat";
		}
		return null;
	}

	public static String getWeekShort2(String month, int day) {
		return getWeekShort2(getCalendar(month, day));
	}

	public static String getWeekShort2(Date date) {
		return getWeekShort2(getCalendar(date));
	}

	public static String getWeekShort2(Calendar calendar) {
		if (calendar == null) {
			return null;
		}
		int i = calendar.get(Calendar.DAY_OF_WEEK);
		switch (i) {
		case Calendar.SUNDAY:
			return "S";
		case Calendar.MONDAY:
			return "M";
		case Calendar.TUESDAY:
			return "T";
		case Calendar.WEDNESDAY:
			return "W";
		case Calendar.THURSDAY:
			return "T";
		case Calendar.FRIDAY:
			return "F";
		case Calendar.SATURDAY:
			return "S";
		}
		return null;
	}

	public static boolean isWorkingDay(String month, int day) {
		return isWorkingDay(getCalendar(month, day));
	}

	public static boolean isWorkingDay(Date date) {
		return isWorkingDay(getCalendar(date));
	}

	public static boolean isWorkingDay(Calendar calendar) {
		if (calendar == null) {
			return false;
		}
		String date = formatDate(calendar.getTime(), DATE_PATTEN_DAY);
		if (getWorkingday().contains(date)) {
			return true;
		}
		if (isWeekend(calendar)) {
			return false;
		}
		return true;
	}

	public static int workingDayAfter(String fromMonth, int fromDay,
			String toMonth, int toDay) {
		return workingDayAfter(getCalendar(fromMonth, fromDay),
				getCalendar(toMonth, toDay));
	}

	public static int workingDayAfter(Date fromDate, Date toDate) {
		return workingDayAfter(getCalendar(fromDate), getCalendar(toDate));
	}

	public static int workingDayAfter(Calendar fromDate, Calendar toDate) {
		if (fromDate == null || toDate == null) {
			return -1;
		}
		if ((fromDate.get(Calendar.YEAR) == toDate.get(Calendar.YEAR))
				&& (fromDate.get(Calendar.MONTH) == toDate.get(Calendar.MONTH))
				&& (fromDate.get(Calendar.DAY_OF_MONTH) == toDate
						.get(Calendar.DAY_OF_MONTH))) {
			return 0;
		}
		if (fromDate.after(toDate)) {
			return -1;
		}
		int i = 0;
		do {
			fromDate.add(Calendar.DAY_OF_MONTH, 1);
			if (isWorkingDay(fromDate)) {
				i++;
			}
		} while (fromDate.before(toDate));
		return i;
	}

	public static Date getNextWorkingDay(int nextDayNumber, String month,
			int day) {
		return getNextWorkingDay(nextDayNumber, getCalendar(month, day));
	}

	public static Date getNextWorkingDay(int nextDayNumber, Date date) {
		return getNextWorkingDay(nextDayNumber, getCalendar(date));
	}

	public static Date getNextWorkingDay(int nextDayNumber, Calendar calendar) {
		if (calendar == null) {
			return null;
		}
		if (nextDayNumber <= 0) {
			return calendar.getTime();
		}
		for (int i = 0; i < nextDayNumber; i++) {
			do {
				calendar.add(Calendar.DAY_OF_MONTH, 1);
			} while (!isWorkingDay(calendar));
		}
		return calendar.getTime();
	}

	public static Date getBeforeWorkingDay(int beforeDayNumber, String month,
			int day) {
		return getBeforeWorkingDay(beforeDayNumber, getCalendar(month, day));
	}

	public static Date getBeforeWorkingDay(int beforeDayNumber, Date date) {
		return getBeforeWorkingDay(beforeDayNumber, getCalendar(date));
	}

	public static Date getBeforeWorkingDay(int beforeDayNumber,
			Calendar calendar) {
		if (calendar == null) {
			return null;
		}
		if (beforeDayNumber <= 0) {
			return calendar.getTime();
		}
		for (int i = 0; i < beforeDayNumber; i++) {
			do {
				calendar.add(Calendar.DAY_OF_MONTH, -1);
			} while (!isWorkingDay(calendar));
		}
		return calendar.getTime();
	}

	public static Calendar getCalendar(String month, int day) {
		Date date = parseDate(month, "yyyy-MM");
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.set(Calendar.DAY_OF_MONTH, day);
		return calendar;
	}

	public static Calendar getCalendar(Date date) {
		if (date == null) {
			return null;
		}
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		return calendar;
	}

	private static Set<String> workingday;

	private static Set<String> getWorkingday() {
		if (workingday == null) {
			workingday = new HashSet<String>();
			workingday.add("2009-10-10");
			workingday.add("2009-10-11");

			workingday.add("2010-02-20");
			workingday.add("2010-02-21");

			workingday.add("2011-01-30");
			workingday.add("2011-02-12");
			workingday.add("2011-04-02");

			workingday.add("2011-10-08");
			workingday.add("2011-10-09");
		}
		return workingday;
	}

	public static int addPriviledge(int priValue, int pri) {
		if (pri > 30 || pri < 1) {
			return priValue;
		}
		return priValue | (int) Math.pow(2, pri - 1);
	}

	public static int deletePriviledge(int priValue, int pri) {
		if (pri > 30 || pri < 1) {
			return priValue;
		}
		return priValue & ~(int) Math.pow(2, pri - 1);
	}

	public static boolean havePriviledge(int priValue, int pri) {
		if (pri > 30 || pri < 1) {
			return false;
		}
		return (priValue & (int) Math.pow(2, pri - 1)) > 0;
	}

	public static Set<Integer> getAllPriviledge(int priValue) {
		Set<Integer> result = new LinkedHashSet<Integer>();
		for (int i = 1; i <= 30; i++) {
			if (havePriviledge(priValue, i)) {
				result.add(i);
			}
		}
		return result;
	}

	public static Map<String, List<String>> getMonthDaysMap(Date startDate,
			Date endDate) {
		Map<String, List<String>> monthDaysMap = new HashMap<String, List<String>>();
		Set<String> months = getMonthArray(startDate, endDate);
		Set<String> days = getDateArray(startDate, endDate);
		for (String month : months) {
			if (monthDaysMap.get(month) == null) {
				monthDaysMap.put(month, new ArrayList<String>());
			}
		}
		for (String day : days) {
			monthDaysMap
					.get(getMonth(DateUtil.parseDate(day, DATE_PATTEN_DAY)))
					.add(day);
		}
		return monthDaysMap;
	}

	public static int getMonthDays(int year, int month) {
		Calendar calendar = Calendar.getInstance();
		calendar.set(Calendar.YEAR, year);//
		calendar.set(Calendar.MONTH, month - 1);//
		int days = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
		return days;
	}

	public static void main(String[] args) {
		Random rnd = new Random(System.currentTimeMillis());
		int p = rnd.nextInt(1);
		System.out.println(p);
	}
}
